package com.hotel.websocketsystem.server;

import com.common.utils.LocalDateTimeToTimeStamp;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.hotel.websocketsystem.mapper.CustomerServiceMessageMapper;
import com.hotel.websocketsystem.pojo.CustomerServiceMessage;
import com.hotel.websocketsystem.pojo.CustomerServiceUser;
import com.hotel.websocketsystem.pojo.SocketMsg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

import static com.hotel.config.rabbitmq.config.TMC_WS_Delay_DirectConfig.TMC_DELAY_EXCHANGE;
import static com.hotel.config.rabbitmq.config.TMC_WS_Delay_DirectConfig.TMC_DELAY_KEY;

@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{nickname}")
public class WebSocketService {
//    消息队列
    private static RabbitTemplate rabbitTemplate;
//    注入持久层
    private static CustomerServiceMessageMapper serviceMessageMapper;
    @Resource
    public void setMapper(CustomerServiceMessageMapper serviceMessageMapper) {
        WebSocketService.serviceMessageMapper = serviceMessageMapper;
    }
    @Resource
    public void setRabbitmq(RabbitTemplate rabbitTemplate) {
        WebSocketService.rabbitTemplate = rabbitTemplate;
    }

    // 存储消息体 初始化容量大小为100
    private static final List<CustomerServiceMessage> messageList = new ArrayList<>(100);

    private String nickname;
    private Session session;

//    用来存放每个客户端对应的Mywebsocket对象
    private static CopyOnWriteArraySet<WebSocketService> webSocketSet=new CopyOnWriteArraySet<>();
//    与某个客户端的连接会话  需要通过它来给客户端发送数据
//    用来记录sessionId，session进行绑定
    private static Map<String,Session> map=new HashMap<String,Session>();
//    连接建立成功调用的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("nickname") String nickname){
        String name =nickname.split("&")[0];  //截取酒店的名称
        String no =nickname.split("&")[1];  //截取酒店的编号
        System.out.println("酒店客户端的名称 ：" + name + "编号为 ：" + no);
        log.info("会话内容：{}",session);
        log.info("当前用户昵称：{}",name);
        Map<String,Object> message=new HashMap<>();//存放消息体
        this.nickname = nickname;
        this.session = session;
        map.put(name,session);
        webSocketSet.add(this);//将当前的客户存放在 集合中
        System.out.println("有新连接加入:" + name + ",当前在线人数为" + webSocketSet.size());
        message.put("type",0); //消息类型，0-连接成功，1-用户消息
        message.put("people",webSocketSet.size()); //在线人数
        message.put("name",name); //昵称
        message.put("aisle",name); //频道号
        log.info("message：{}",message);
        this.session.getAsyncRemote().sendText(new Gson().toJson(message));

    }

//    发送消息
    @OnMessage
    public void onMessage(String message,Session session,@PathParam("nickname") String nickname){
        System.out.println("客户端发来消息 ：" + nickname + " : " + message);
        String name =nickname.split("&")[0];  //截取酒店的名称
        String no =nickname.split("&")[1];  //截取酒店的编号
        System.out.println("酒店客户端的名称 ：" + name + "消息为 ：" + message);
        //从客户端传过来的数据是json数据，所以这里使用jackson进行转换为SocketMsg对象，
        // 然后通过socketMsg的type进行判断是单聊还是群聊，进行相应的处理
        ObjectMapper objectMapper=new ObjectMapper();
        SocketMsg socketMsg;
        try {
            socketMsg=objectMapper.readValue(message,SocketMsg.class );// 通过ObjectMapper提供的readValue读取前端发送过来的消息对象，通过映射生成一个SocketMsg对象
            if(socketMsg.getType() == 1){
//                单聊   匹配发送者和接受者
                socketMsg.setFromUser(name); //发送者
                //如果list集合中的数据  量超过10 自动添加到数据库  并且清空缓存  否则继续 添加到list
                if(messageList.size()>10){
                    //                    将聊天集合写入文件
                    writeMassageToTxt(messageList);
                    addMessageList(messageList);
                    messageList.clear(); //并且清空缓存
                }else {
                    CustomerServiceMessage customerServiceMessage= new CustomerServiceMessage();
                    customerServiceMessage.setUserAdmin01(socketMsg.getFromUser());
                    customerServiceMessage.setUserAdmin02(socketMsg.getToUser());
//                   将消息进行封装
                    String msg=customerServiceMessage.getUserAdmin01()+" "+"发送给" +" "+customerServiceMessage.getUserAdmin02()+message;
                    System.out.println(msg);
                    customerServiceMessage.setMessage(msg);
//                    创建时间
                    customerServiceMessage.setCreateTime(LocalDateTime.now());
//                    创建过期时间   LocalDateTime.now().plusDays(7)   将此刻的时间+7
                    customerServiceMessage.setOverTime(LocalDateTime.now().plusDays(7));
//                    将数据添加到list集合中
                    messageList.add(customerServiceMessage);


                }
                Session fromSession=map.get(socketMsg.getFromUser());//发送者的会话
                Session toSession=map.get(socketMsg.getToUser());//接收者的会话

//                传给发送者
                if(toSession != null) {
                    Map<String,Object> m=new HashMap<>();
                    m.put("type",1); // 表示单聊 0 表示群聊
                    m.put("nickname",name);
                    m.put("msg",socketMsg.getMsg());
                    fromSession.getAsyncRemote().sendText(new Gson().toJson(m));
                    toSession.getAsyncRemote().sendText(new Gson().toJson(m));
                }else{
//                    发送给发送者 getAsyncRemote提供一个非阻塞式的异步发送消息方法
                    fromSession.getAsyncRemote().sendText("系统消息提示：对方不在线或者输入的频道号不正确！");
                }
            }else{
//                群发消息
                broadcast(nickname + ": " + socketMsg.getMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    //    群发消息
    public void broadcast(String message) {
        for (WebSocketService item : webSocketSet) {
            item.session.getAsyncRemote().sendText(message);//异步发送消息.
        }
    }
//    发送错误时调用
    @OnError
    public void onError(Session session,Throwable error){
        System.out.println("发生错误！");
        error.printStackTrace();
    }

    //    关闭连接调用的方法
    @OnClose
    public void onClose(){
//        当会话关闭 从集合中移除这个用户
        webSocketSet.remove(this);
        System.out.println("有一连接关闭！当前在线人数为" + webSocketSet.size());
//        当会话关闭  添加到数据库、
        addMessageList(messageList);


    }
//    添加到数据库
    public void addMessageList(List<CustomerServiceMessage> messagelist){
        // 消息体
        StringBuffer msgList = new StringBuffer();

//       将数组遍历并添加到数据库
        messagelist.forEach(k->{
            msgList.append(k.getMessage());
            System.out.println("zcxxxxx"+msgList.append(k.getMessage()));
        });
        // 发送者
        CustomerServiceMessage customerServiceMessage=new CustomerServiceMessage();
        customerServiceMessage.setUserAdmin01(messagelist.get(0).getUserAdmin01());
        customerServiceMessage.setUserAdmin02(messagelist.get(0).getUserAdmin02());
        customerServiceMessage.setMessage(msgList.toString());
        customerServiceMessage.setCreateTime(LocalDateTime.now());
//        将过期时间设置为七天
        customerServiceMessage.setOverTime(LocalDateTime.now().plusDays(7));
//        customerServiceMessage.setOverTime(LocalDateTime.now().plusSeconds(20));
        //  将数据放入数据库
        int insert = serviceMessageMapper.insert(customerServiceMessage);
        if (insert > 0) {
            //  计算时间差
    //        将本地时间转换成时间戳（毫秒数）进行计算
            long start = customerServiceMessage.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
            long end = customerServiceMessage.getOverTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
    //        差值
            Integer time_value = Math.toIntExact(end - start);
            log.info("时间差：{}",time_value);
//            System.out.println("时间差值为：" + time_value);
    //        发消息给生产者                 交换机    密钥  对象
            rabbitTemplate.convertAndSend(TMC_DELAY_EXCHANGE,TMC_DELAY_KEY,customerServiceMessage,dsg->{
    //            设置消息延迟发送时间
                dsg.getMessageProperties().setDelay(time_value);
                return dsg;
            });
        }
    }

//    将聊天记录写入文件夹
    public void writeMassageToTxt(List list) throws Exception {
//        创建文件夹
        File file=new File("D:\\chatMessage");
//        创建一个子目录
        file.mkdir();
//        创建一个txt文件
        File txt=new File("D:\\chatMessage\\message.txt");
        try {
            txt.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
//        将这个文件写入
        BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:\\chatMessage\\message.txt")));
        list.forEach(s->{
            try {
//                将每个对象遍历转成字符串  写入
                writer.write(s.toString());
//                刷新
                writer.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
//        关闭流
        writer.close();
    }

}
